using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Xml.Serialization;
using Microsoft.Xna.Framework;

using Falon.Items;
using Najak;

namespace Falon
{
	static class Program
	{
		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		static void Main(string[] args)
		{
			_PluginNajak();

			if (false)
			{	// Hosted inside an Editor Window
				Application.EnableVisualStyles();
				Application.SetCompatibleTextRenderingDefault(false);
				Application.Run(new Najak.Editor.EditorWindow());
			}
			else
			{	// Hosted as XNA Game, with Full Screen option
				using (Najak.RenderControls.AppHost appHost = new Najak.RenderControls.AppHost())
				{
					appHost.Run();
				}
			}

			//using (Game game = new Game())
			//{
			//    game.Run();
			//}
		}

		static private void _PluginNajak()
		{
			Scene.GetTileModel = GetTileModel;
			Scene.CreateGamePlayer = CreateGamePlayer;
			Scene.CaptureDynamicContent = CaptureDynamicSceneContent;
			Scene.State.ApplyDynamicContent = ApplyDynamicContentToScene;
			Scene.State.LoadFromFile = LoadSceneContent;
			Scene.State.SaveToFile = SaveSceneContent;
			Najak.App.Create = Falon.Game.Create;

			Najak.Editor.EditorWindow.GetEntityByName = GetEntityByName;
			Najak.Editor.EditorWindow.GetTileByName = GetTileByName;
		}

		static private void SaveSceneContent(Scene.State s)
		{
			SceneState ss = new SceneState()
			{
				CurrentSceneName = s.CurrentSceneName,
				SceneContent = s.SceneContent as List<Info>,
				StaticContent = s.StaticContent
			};

			XmlSerializer ser = new XmlSerializer(typeof(SceneState));
			System.IO.FileStream stream = new System.IO.FileStream(Scene.Manager.SceneFolder + s.CurrentSceneName + ".xml", System.IO.FileMode.Create);
			ser.Serialize(stream, ss);

			stream.Close();
		}

		static private Scene.State LoadSceneContent(string name)
		{
			XmlSerializer ser = new XmlSerializer(typeof(SceneState));
			System.IO.FileStream stream = new System.IO.FileStream(Scene.Manager.SceneFolder + name + ".xml", System.IO.FileMode.Open);

			SceneState s = ser.Deserialize(stream) as SceneState;

			stream.Close();

			Scene.State ss = new Scene.State()
			{
				CurrentSceneName = s.CurrentSceneName,
				SceneContent = s.SceneContent,
				StaticContent = s.StaticContent
			};

			return ss;
		}

		static private void ApplyDynamicContentToScene(Scene scene, object content)
		{
			List<Info> dc = content as List<Info>;

			foreach (Info info in dc)
			{
				info.Create(scene);
			}
		}

		static private PlayerEntity CreateGamePlayer()
		{
			return new GodPlayer(true);
		}

		static private Tile GetTileModel(char tileType)
		{
			switch (tileType)
			{
				case '.': return Assets.Tiles.Floor;
				case 'O': return Assets.Tiles.SecretDoor;
				case 'N': return Assets.Tiles.NonPath;
				case '#': return Assets.Tiles.Wall;
				case '=': return Assets.Tiles.MapExpander;
				case 'A': return Assets.Tiles.Floor;
				case 'E': return Assets.Tiles.Floor;
				case 'D': return Assets.Tiles.Floor;
				default:
					return null;
				//throw new NotSupportedException(String.Format("Unsupported tile type character '{0}' at coordinate {1}, {2}.", tileType, x, y));
			}
		}

		static private Tile GetTileByName(string name)
		{
			switch (name)
			{
				case "None": return null;
				case "Floor": return Assets.Tiles.Floor;
				case "Wall": return Assets.Tiles.Wall;
				case "Portal":
					int id = _PromptUserForPortalID();
					return new Portal(id, "Tiles/Portal_1", null);

				case "Secret Door": return Assets.Tiles.SecretDoor;
				case "Map Expander": return Assets.Tiles.MapExpander;
				default: return null;
			}
		}

		static private Entity GetEntityByName(string name)
		{
			switch (name)
			{
				case "None": return null;
				case "Barrel": return Assets.Entities.Barrel;
				case "Infantry1": return new Units.Infantry(1, Assets.Weapons.Spear.Clone() as Weapon);
				case "Infantry2": return new Units.Infantry(2, Assets.Weapons.Spear.Clone() as Weapon);
				case "SpearThrower1": return new Units.Infantry(1, Assets.Weapons.ThrowingSpear.Clone() as Weapon);
				case "SpearThrower2": return new Units.Infantry(2, Assets.Weapons.ThrowingSpear.Clone() as Weapon);
				default: return null;
			}
		}

		static private int _PromptUserForPortalID()
		{
			return 0;
		}

		static private object CaptureDynamicSceneContent(Scene scene)
		{
			object content;

			if (!Scene.DynamicContentRegistry.TryGetValue(scene.Name, out content))
			{
				content = new List<Info>();
				Scene.DynamicContentRegistry.Add(scene.Name, content);
			}

			List<Info> dc = content as List<Info>;

			dc.Clear();
			foreach (Entity entity in scene.Entities)
			{
				ExplosiveBarrel ep = entity as ExplosiveBarrel;
				if (ep != null)
				{
					ExplosiveBarrelInfo info = new ExplosiveBarrelInfo(ep);
					dc.Add(info);
				}
				Units.Infantry inf = entity as Units.Infantry;
				if (inf != null)
				{
					InfantryInfo info = new InfantryInfo(inf);
					dc.Add(info);
				}

			}
			return dc;
		}

	}

	public class SceneState
	{
		public string CurrentSceneName;
		public List<Info> SceneContent;
		public string StaticContent;

		public SceneState() { }
	}

}

